/*
#
#  Copyright 2011 Matthew Jannace
#
#  This file is part of RoboCode BlackHoleAgent
#
#  RoboCode BlackHoleAgent is free software: you can redistribute it and/or
#  modify it under the terms of the GNU General Public License as
#  published by the Free Software Foundation, either version 3 of the
#  License, or (at your option) any later version.
#
#  RoboCode BlackHoleAgent is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
#  General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with RoboCode BlackHoleAgent. If not, see
#  <http://www.gnu.org/licenses/>.
#
 */
package com.jannaceltd.TeamBlackHoleBeer.Utilities;

import java.awt.Point;
import java.awt.geom.Point2D;

/**
 * @author Christopher Fuhrman (christopher.fuhrman@gmail.com)
 * @version 2006-09-27
 */
public class PolygonUtilities {

    /**
     * Function to calculate the area of a polygon, according to the algorithm
     * defined at http://local.wasp.uwa.edu.au/~pbourke/geometry/polyarea/
     *
     * @param polyPoints
     *            array of points in the polygon
     * @return area of the polygon defined by pgPoints
     */
    public static double area(Point2D[] polyPoints) {
        int i, j, n = polyPoints.length;
        double area = 0;

        for (i = 0; i < n; i++) {
            j = (i + 1) % n;
            area += polyPoints[i].getX() * polyPoints[j].getY();
            area -= polyPoints[j].getX() * polyPoints[i].getY();
        }
        area /= 2.0;
        return (area);
    }

    /**
     * Function to calculate the center of mass for a given polygon, according
     * ot the algorithm defined at
     * http://local.wasp.uwa.edu.au/~pbourke/geometry/polyarea/
     *
     * @param polyPoints
     *            array of points in the polygon
     * @return point that is the center of mass
     */
    public static Point2D centerOfMass(Point2D[] polyPoints) {
        double cx = 0, cy = 0;
        double area = area(polyPoints);
        // could change this to Point2D.Float if you want to use less memory
        Point2D res = new Point2D.Double();
        int i, j, n = polyPoints.length;

        double factor = 0;
        for (i = 0; i < n; i++) {
            j = (i + 1) % n;
            factor = (polyPoints[i].getX() * polyPoints[j].getY()
                    - polyPoints[j].getX() * polyPoints[i].getY());
            cx += (polyPoints[i].getX() + polyPoints[j].getX()) * factor;
            cy += (polyPoints[i].getY() + polyPoints[j].getY()) * factor;
        }
        area *= 6.0f;
        factor = 1 / area;
        cx *= factor;
        cy *= factor;
        res.setLocation(cx, cy);
        return res;
    }

    /**
     * Computes the intersection between two lines. The calculated point is approximate,
     * since integers are used. If you need a more precise result, use doubles
     * everywhere.
     * (c) 2007 Alexander Hristov. Use Freely (LGPL license). http://www.ahristov.com
     *
     * @param x1 Point 1 of Line 1
     * @param y1 Point 1 of Line 1
     * @param x2 Point 2 of Line 1
     * @param y2 Point 2 of Line 1
     * @param x3 Point 1 of Line 2
     * @param y3 Point 1 of Line 2
     * @param x4 Point 2 of Line 2
     * @param y4 Point 2 of Line 2
     * @return Point where the segments intersect, or null if they don't
     */
    public static Point intersection(
            int x1, int y1, int x2, int y2,
            int x3, int y3, int x4, int y4) {
        int d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
        if (d == 0) {
            return null;
        }

        int xi = ((x3 - x4) * (x1 * y2 - y1 * x2) - (x1 - x2) * (x3 * y4 - y3 * x4)) / d;
        int yi = ((y3 - y4) * (x1 * y2 - y1 * x2) - (y1 - y2) * (x3 * y4 - y3 * x4)) / d;


        return new Point(xi, yi);
    }

    /**
     * Computes the intersection between two lines. The calculated point is approximate,
     * since integers are used. If you need a more precise result, use doubles
     * everywhere.
     *
     * Modified by Matthew Jannace but based on the work of Alexander Hristov's
     * intersection method
     * 
     * @param L1_P1
     * @param L1_P2
     * @param L2_P1
     * @param L2_P2
     * @return
     */
    public static Point2D intersection(Point2D L1_P1, Point2D L1_P2, Point2D L2_P1, Point2D L2_P2) {
        double x1 = L1_P1.getX();
        double y1 = L1_P1.getY();

        double x2 = L1_P2.getX();
        double y2 = L1_P2.getY();

        double x3 = L2_P1.getX();
        double y3 = L2_P1.getY();

        double x4 = L2_P2.getX();
        double y4 = L2_P2.getY();


        double d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
        if (d == 0) {
            return null;
        }

        double xd = ((x3 - x4) * (x1 * y2 - y1 * x2) - (x1 - x2) * (x3 * y4 - y3 * x4)) / d;
        double yd = ((y3 - y4) * (x1 * y2 - y1 * x2) - (y1 - y2) * (x3 * y4 - y3 * x4)) / d;

        return new Point2D.Double(xd, yd);
    }
}
